﻿using System;
using System.Collections.Generic;
using System.Windows.Media;
using System.Windows.Input;
using Bling.Core;
using Bling.Util;
using Bling.DSL;
using Bling.WPF;
using Bling.WPF.Custom;
using Bling.Graphics;
using Bling.DX;
using Bling.Matrices;
using Bling.WPF3D;
using Bling.Shaders;

namespace Bling.Example {
  public class Curtain : HasDX10Canvas {
    public Curtain()
      // by passing true to base, an overlay window will be created.
      : base(true) {
      var Self = this.Bl();

      var UriA = "Resources/4147-diffuse.jpg".MakePackUri(typeof(Curtain));
      var UriB = "Resources/4147-normal.jpg".MakePackUri(typeof(Curtain));
      var source = UriA.ImageFor().Bl();


      Texture2Bl DiffuseImage = new ImageTexture<D2>(UriA);
      Texture2Bl NormalImage = new ImageTexture<D2>(UriB);
      var ratio = Self.Size - new Double2Bl(0, 100);
      ratio = ratio / source.Size;

      int Dim = 500;
      Host.Size = 100;
      Host.Size[Self.Loaded].Bind = (source.Size * ratio.Min()).Max(100); // host size must be constant!
      Host.LeftTop = 0d;
      // background of overlay can't be transparent or it won't receive input. 
      // It can be a very transparent color though, go fig. 
      OverlayContent.Background = new SolidColorBrushBl() { Color = Colors.White, Opacity = OverlayContent.IsMouseOver.Condition(.15d, .01d), };

      var RenderTargetA = new RenderTargetTexture<D2>(Dim, Dim) {
        Format = new TextureFormat.Typical() {
          Width = TextureFormat.ChannelWidth.WORD,
          Type = TextureFormat.ChannelType.FLOAT,
        },
      };
      var RenderTargetB = new RenderTargetTexture<D2>(Dim, Dim) {
        Format = new TextureFormat.Typical() {
          Width = TextureFormat.ChannelWidth.WORD,
          Type = TextureFormat.ChannelType.FLOAT,
        },
      };
      RenderTargetBl RenderA = RenderTargetA.AsRenderTarget, RenderB = RenderTargetB.AsRenderTarget;
      Texture2Bl TextureA = RenderTargetA, TextureB = RenderTargetB;

      bool SwapFromTo0 = true;
      var Swap = true.Bl().StatefulMap<bool, BoolBl>(b => SwapFromTo0);
      var Face = new FaceMesh();
      { // handle the mouse
        var MouseOverContent = OverlayContent.Mouse.Position / OverlayContent.Size;
        MouseOverContent = MouseOverContent * 2d - 1d;
        MouseOverContent = MouseOverContent * new Double2Bl(+1, -1);

        var re = Device.Render(Face, (Entry, vertex) => {
          var scale = true.Bl().Condition(.01d.Bl(), 0d.Bl());
          var Transform =
            Matrix4Bl.MakeTranslate(MouseOverContent.AddZ(0)) * Matrix4Bl.MakeScale(scale);
          var Pos = Transform.Transform(Entry.Position);
          //Pos = OverlayContent.Keys[Key.Space].Condition(Pos, new Double3Bl(100000, 10000, 10000));
          vertex.Position = Pos;

          vertex.Color = Colors.Red;
          //OverlayContent.Keys[Key.Space].Condition(Colors.Red.Bl(), noColor);
          //Colors.Red;
        });
        re.Target = Swap.Condition(RenderA, RenderB);
      }
      var Radius = new LabelSliderBl(this) {
        Width = Host.Width,
        LeftTop = Host.LeftBottom,
        LabelName = "Radius",
        Minimum = .001,
        Maximum = .020,
        Value = .009,
      };
      var M = new LabelSliderBl(this) {
        Width = Host.Width,
        LeftTop = Radius.LeftBottom,
        LabelName = "M",
        Minimum = .0,
        Maximum = .3,
        Value = .1,
      };
      var N = new LabelSliderBl(this) {
        Width = Host.Width,
        LeftTop = M.LeftBottom,
        LabelName = "N",
        Minimum = .0,
        Maximum = .003,
        Value = .001,
      };

      { // diffusion
        var re = Device.Render(Face, (Entry, vertex) => {
          vertex.Position = Entry.Position.AddW(1);
          var uv = Entry.Texture;
          uv = new Double2Bl(uv.X, 1d - uv.Y);
          var Tex = Swap.Condition(TextureA, TextureB);

          //var clr = Radius.Value.PerPixel().Diffusion(20)[Tex][uv];
          var clr = ShaderLib.Sample(Tex, uv, Radius.Value.PerPixel(), 20);
          clr = ShaderLib.Transfer(Tex[uv].ScRGB, clr, M.Value.PerPixel(), N.Value.PerPixel());
          clr = clr.Saturate;

          vertex.Color = clr.Saturate;

        });
        re.Target = Swap.Condition(RenderB, RenderA);
      }
      {
        var re = Device.Render(Face, (Entry, vertex) => {
          vertex.Position = Entry.Position.AddW(1);
          var uv = Entry.Texture.PerPixel();
          uv = new Double2Bl(uv.X, 1d - uv.Y);
          var redness = Swap.Condition(TextureB, TextureA)[uv].ScR;

          vertex.Color = redness.Lerp(DiffuseImage[uv], NormalImage[uv]);


          //vertex.Color = Swap.Condition(TextureB, TextureA)[uv];
        });

        re.Post = () => SwapFromTo0 = !SwapFromTo0;
      }
    }
  }
}